"""
File Name: Pycharm
Description:   reddit_account
Author: Panwj
Date: 2025/9/6 10:26
"""
import json
import random
import time

import requests
from faker import Faker

from src.register.register_base import RegisterBase

from loguru import logger

from src.util.email_creator import create_box

faker = Faker()


class RedditAccount(RegisterBase):
    name = 'reddit'

    def __init__(self):
        super().__init__()
        self.home_url = 'https://www.reddit.com/register/'

    def get_email_code(self, email, password='shuyuan008'):
        retry_size = 60
        while retry_size:
            try:
                headers = {
                    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
                    'accept-language': 'zh-CN,zh;q=0.9',
                    'cache-control': 'max-age=0',
                    'priority': 'u=0, i',
                    'upgrade-insecure-requests': '1',
                    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36',
                }

                response = requests.get(
                    f'https://crawl-fs.datatell.com.cn/get_email?email={email}&password={password}&to_code=1',
                    headers=headers,
                )
                if response.status_code == 200 and response.text:
                    return response.text
                time.sleep(1)
            except:
                time.sleep(1)

    def random_select_question_and_answoer(self):
        """随机选择一个话题选项"""
        try:
            # 等待话题区域加载完成
            self.page.wait.ele_displayed('.topic-section', timeout=10)

            # 查找所有话题按钮
            topic_buttons = self.page.eles('.topic-container button.topic')

            if not topic_buttons:
                print("未找到话题按钮")
                return False

            # 随机选择一个按钮
            selected_button = random.choice(topic_buttons)

            # 获取话题名称
            topic_name = selected_button.ele('span.select-none').text
            print(f"随机选择的话题: {topic_name}")

            # 点击按钮
            selected_button.click()

            # 等待一下，确保点击生效
            time.sleep(1)

            # 验证是否选择成功（检查按钮是否被选中）
            # 根据HTML结构，被选中的按钮会有特定的类名变化
            button_classes = selected_button.attr('class')
            if 'peer-checked' in button_classes:
                print(f"成功选择话题: {topic_name}")
                return True
            else:
                print(f"可能未成功选择话题: {topic_name}")
                # 尝试再次点击
                selected_button.click()
                time.sleep(0.5)
                return True

        except Exception as e:
            print(f"选择话题时出错: {e}")
            return False

    def select_gender(self, gender_value='MALE'):
        """选择性别"""
        # 等待页面加载
        # try:
        #     button = self.page.ele(
        #         f'xpath://span[@slot="onboarding"] >>> faceplate-partial >>> onboarding-flow >>> shreddit-slotter >>> ob-gender-selection >>> auth-flow-modal >>> button[@name="genderEnum" and @value="{gender_value}"]')
        #     if button:
        #         button.click()
        #         return True
        # except:
        #     pass

        # 如果上面失败，则使用JavaScript递归查找
        js_code = """
                        function findButtonInShadowRoot(root, name, value) {
                           const selector = `button[name="${name}"][value="${value}"]`;
                           const button = root.querySelector(selector);
                           if (button) {
                               return button;
                           }

                           const elements = root.querySelectorAll('*');
                           for (let i = 0; i < elements.length; i++) {
                               const el = elements[i];
                               if (el.shadowRoot) {
                                   const result = findButtonInShadowRoot(el.shadowRoot, name, value);
                                   if (result) {
                                       console.log(result);
                                       return result;
                                   }
                               }
                           }
                           return null;
                        }

                        const host = document.querySelector('span[slot="onboarding"]');
                        if (!host) {
                           return false;
                        }

                        let root = host;
                        if (host.shadowRoot) {
                           root = host.shadowRoot;
                        }

                        const button = findButtonInShadowRoot(root, 'genderEnum', arguments[0]);
                        if (button) {
                           console.log("找到点击按钮");
                           button.click();
                           return true;
                        }
                        return false;
                        """

        success = self.page.run_js(js_code, 'MALE')

        return success

    def select_interests(self, min_select=1, max_select=5):
        """
        选择兴趣标签

        Args:
            min_select: 最少选择数量
            max_select: 最多选择数量
        """
        # 等待兴趣选择页面加载
        self.page.wait.ele_displayed('xpath://auth-flow-modal[@pagename="onboarding_interest"]', timeout=20)

        # 等待标签加载完成
        time.sleep(3)

        # 执行选择标签的JS代码
        js_select = """
        (function() {
            // 递归查找Shadow DOM中的元素
            function findInShadowRoot(root, selector) {
                // 先在当前shadow root中查找
                const elements = root.querySelectorAll(selector);
                if (elements.length > 0) {
                    return Array.from(elements);
                }

                // 如果没有找到，递归查找所有有shadowRoot的子元素
                const allElements = root.querySelectorAll('*');
                let results = [];
                for (const el of allElements) {
                    if (el.shadowRoot) {
                        const found = findInShadowRoot(el.shadowRoot, selector);
                        results = results.concat(found);
                    }
                }
                return results;
            }

            // 从document开始查找所有未选中的topic checkbox
            const allCheckboxes = findInShadowRoot(document, 'input[name="topic-id"]');
            const uncheckedCheckboxes = allCheckboxes.filter(cb => !cb.checked);

            // 随机选择至少minSelect个，最多maxSelect个未选中的checkbox
            const minSelect = %d;
            const maxSelect = %d;
            let count = Math.min(maxSelect, uncheckedCheckboxes.length);
            count = Math.max(minSelect, count); // 至少选择minSelect个

            const selectedCheckboxes = [];
            for (let i = 0; i < count; i++) {
                const randomIndex = Math.floor(Math.random() * uncheckedCheckboxes.length);
                selectedCheckboxes.push(uncheckedCheckboxes[randomIndex]);
                uncheckedCheckboxes.splice(randomIndex, 1);
            }

            // 点击每个选中的checkbox对应的button
            selectedCheckboxes.forEach(cb => {
                const button = findInShadowRoot(document, `button#${cb.id}`)[0];
                if (button) {
                    button.click();
                }
            });

            return selectedCheckboxes.length;
        })();
        """ % (min_select, max_select)

        selected_count = self.page.run_js(js_select)
        return selected_count

    def click_continue(self):
        js_continue = r"""
           (function() {
               // 递归查找 Shadow DOM 中的元素
               function findInShadowRoot(root, selector) {
                   try {
                       const direct = (root.querySelectorAll && root.querySelectorAll(selector)) || [];
                       if (direct && direct.length) return Array.from(direct);
                   } catch (e) {
                       // selector might not apply at this root
                   }
    
                   const all = (root.querySelectorAll && root.querySelectorAll('*')) || [];
                   let results = [];
                   for (const el of all) {
                       if (el.shadowRoot) {
                           const found = findInShadowRoot(el.shadowRoot, selector);
                           if (found && found.length) results = results.concat(found);
                       }
                   }
                   return results;
               }
    
               function isVisible(el) {
                   if (!el) return false;
                   const style = getComputedStyle(el);
                   if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) === 0) return false;
                   const rect = el.getBoundingClientRect();
                   return rect.width > 0 && rect.height > 0;
               }
    
               function clickWithEvents(el) {
                   try { el.focus && el.focus(); } catch(e){}
                   const events = ['pointerdown','mousedown','pointerup','mouseup','click'];
                   for (const ev of events) {
                       const me = new MouseEvent(ev, { bubbles: true, cancelable: true, composed: true });
                       el.dispatchEvent(me);
                   }
                   // fallback to native click
                   try { el.click && el.click(); } catch(e){}
               }
    
               // 1) 触发所有已选 topic 的 input/change，保证框架能看到状态变化
               const topicInputs = findInShadowRoot(document, 'input[name="topic-id"]');
               let checkedCount = 0;
               for (const inp of topicInputs) {
                   try {
                       if (inp.checked) {
                           checkedCount++;
                           inp.dispatchEvent(new Event('input', { bubbles: true, cancelable: true, composed: true }));
                           inp.dispatchEvent(new Event('change', { bubbles: true, cancelable: true, composed: true }));
                       }
                   } catch (e) {}
               }
    
               // 2) 尝试在与 topics 同一 root 中查找 primaryButton 的 continue
               const topics = findInShadowRoot(document, '#topics')[0] || findInShadowRoot(document, '[id="topics"]')[0];
               const rootsToSearch = [];
               if (topics && topics.getRootNode) {
                   rootsToSearch.push(topics.getRootNode());
               }
               // 也在 document 上搜索作为后备
               rootsToSearch.push(document);
    
               const btnSelectors = 'div[slot="primaryButton"] button, button.continue, button[type="submit"], button';
    
               for (const r of rootsToSearch) {
                   let candButtons = [];
                   try {
                       candButtons = Array.from((r.querySelectorAll && r.querySelectorAll(btnSelectors)) || []);
                   } catch (e) {}
                   for (const b of candButtons) {
                       const txt = (b.textContent || '').trim();
                       const matchesText = txt.includes('继续') || txt.includes('Continue');
                       if (matchesText) {
                           // prefer enabled & visible button
                           if (!b.disabled && isVisible(b)) {
                               clickWithEvents(b);
                               return true;
                           }
                       }
                   }
               }
    
               // 3) 全局 shadow-search 作为 fallback：找到任意可见且未禁用的“继续”按钮
               const allButtons = findInShadowRoot(document, 'button');
               for (const b of allButtons) {
                   const txt = (b.textContent || '').trim();
                   if ((txt.includes('继续') || txt.includes('Continue')) && !b.disabled && isVisible(b)) {
                       clickWithEvents(b);
                       return true;
                   }
               }
    
               // 4) 如果找到了“继续”但它被 disabled（且我们确实有已选主题），尝试移除 disabled 并点击（最后手段）
               if (checkedCount > 0) {
                   for (const b of allButtons) {
                       const txt = (b.textContent || '').trim();
                       if ((txt.includes('继续') || txt.includes('Continue')) && isVisible(b)) {
                           try { b.removeAttribute && b.removeAttribute('disabled'); b.disabled = false; } catch(e){}
                           clickWithEvents(b);
                           return true;
                       }
                   }
               }
    
               return false;
           })();
           """
        return self.page.run_js(js_continue)

    def start_register(self):
        self.load_page()
        self.page.get(self.home_url)
        email = self.page.wait.ele_displayed('xpath://*[@id="register-email"]', timeout=20)
        if email:
            logger.info("开始注册账号！！！")
            email.clear()
            email_name = faker.email().split('@')[0]
            email_address, email_password = (
                create_box(email_name))

            if email_address:
                email.click()
                email.input(email_address)
                button = self.page.ele('xpath://button[contains(@class, "continue") and contains(@class, "oidc")]')
                time.sleep(1)
                button.click()
                code_element = self.page.wait.ele_displayed('xpath://*[@name="code"]', timeout=20)
                if code_element:
                    email_code = self.get_email_code(email_address, email_password)
                    if email_code:
                        code_element.click()
                        code_element.input(email_code)

                        #             email-verification-submit
                        self.page.ele('xpath://button[@id="email-verification-submit"]').click()

                        set_password_element = self.page.wait.ele_displayed('xpath://*[@name="password"]', timeout=20)
                        set_password_element.click()

                        account_password = 'shuyuan008'
                        set_password_element.input('shuyuan008')

                        # 没成功
                        retry_size = 10
                        while retry_size:
                            try:
                                continue_btn = self.page.wait.ele_displayed(
                                    'xpath://button[contains(@class, "create")]')
                                try:
                                    continue_btn.scroll.to_center()
                                    if continue_btn:
                                        continue_btn.click()
                                        time.sleep(3)
                                except:
                                    break
                                if not continue_btn:
                                    break

                            except Exception as e:
                                pass
                            retry_size -= 1

                        # 跳过性别,todo 这里没有成功
                        # 6. 随机选择：男性 / 女性 / 非二元性别 / 跳过
                        choices = ["FEMALE", "MALE", "NON_BINARY"]
                        choice = random.choice(choices)

                        self.select_gender(choice)
                        max_size = random.randint(3, 8)
                        # 选择心情爱好
                        self.select_interests(max_select=max_size)

                        self.click_continue()

                        #
                        time.sleep(10)
                        self.page.refresh()

                        cookies = json.dumps(self.page.cookies())
                        self.save_cookies(email_address, email_password, account_password, cookies)

            else:
                logger.error('没有获取到验证码')


if __name__ == '__main__':
    RedditAccount().start_register()
